package concurrent.futuretest;

import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;

/**
 * CompletableFuture是java8提供的多线程类
 * <p>
 * Future接口可以构建异步应用，但依然有其局限性。它很难直接表述多个Future 结果之间的依赖性。实际开发中，我们经常需要达成以下目的.
 * 将两个异步计算合并为一个——这两个异步计算之间相互独立，同时第二个又依赖于第一个的结果。
 * 等待 Future 集合中的所有任务都完成。
 * 仅等待 Future集合中最快结束的任务完成（有可能因为它们试图通过不同的方式计算同一个值），并返回它的结果。
 * 通过编程方式完成一个Future任务的执行（即以手工设定异步操作结果的方式）。
 * 应对 Future 的完成事件（即当 Future 的完成事件发生时会收到通知，并能使用 Future 计算的结果进行下一步的操作，不只是简单地阻塞等待操作的结果）
 * 新的CompletableFuture类将使得这些成为可能。
 */
public class CompletableFutureTest {

  ThreadPoolExecutor executor = new ThreadPoolExecutor(
      Runtime.getRuntime().availableProcessors(),
      16,
      20,
      TimeUnit.SECONDS,
      new LinkedBlockingQueue<>(100)
  );

  @Test
  public void test1() throws ExecutionException, InterruptedException {

    // 无结果计算
    CompletableFuture<Void> noFuture1 = CompletableFuture.runAsync(() -> {
//      System.out.println(Thread.currentThread().isDaemon());
    });

    CompletableFuture<Void> noFuture2 = CompletableFuture.runAsync(() -> {
//      System.out.println("nothing to return");
    }, executor);


    // 有结果计算
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
      try {
        TimeUnit.SECONDS.sleep(2);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      return "result1";
    });
    System.out.println(future1.getNow(null));

    // future1执行结束后执行下列代码
    future1.thenAccept(result -> {
      System.out.println(result + result);
    });
    future1.thenAcceptAsync(result -> {
      System.out.println(result + result);
    });

    CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
      try {
        TimeUnit.SECONDS.sleep(2);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      return "result2";
    }, executor);
    System.out.println(future2.getNow(null));


    CompletableFuture<String> future3 = CompletableFuture.completedFuture("rrr");
    String result3 = future3.getNow(null);
    System.out.println(result3);

    System.out.println("\n=======");
    System.out.println(future1.get());
    System.out.println(future2.get());
    System.out.println("over");
  }

  @Test
  public void test2() throws InterruptedException {

    System.out.println("第一条线=======");
    List<Future<Object>> futures = executor.invokeAll(Arrays.asList(
        () -> {
          return 111;
        },
        () -> {
          TimeUnit.SECONDS.sleep(2);
          return 222;
        })
    );

    // 结果显示，多个线程的结果必须都执行完成才会继续执行下列代码
    System.out.println("第二条线=======");
    futures.stream().forEach(e -> {
      try {
        System.out.println(e.get());
      } catch (InterruptedException e1) {
        e1.printStackTrace();
      } catch (ExecutionException e1) {
        e1.printStackTrace();
      }
    });
  }

}
